From 91741f6b634cc1317beefa062ab7b5547735fc87 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 30 Dec 2016 06:46:34 +0100 Subject: [PATCH] vulkan: Handle opacity nodes Well, "handle" them actually. We still draw the node's child using Cairo, but we apply the opacity manually now. --- gsk/Makefile.am | 4 +- gsk/gskvulkaneffectpipeline.c | 129 ++++++++++++++++++ gsk/gskvulkaneffectpipelineprivate.h | 32 +++++ gsk/gskvulkanrender.c | 6 +- gsk/gskvulkanrenderpass.c | 120 ++++++++++++++++ gsk/gskvulkanrenderprivate.h | 3 + .../vulkan/opacity-clip-rounded.frag.glsl | 64 +++++++++ .../vulkan/opacity-clip-rounded.frag.spv | Bin 0 -> 5584 bytes .../vulkan/opacity-clip-rounded.vert.glsl | 56 ++++++++ .../vulkan/opacity-clip-rounded.vert.spv | Bin 0 -> 5124 bytes gsk/resources/vulkan/opacity-clip.frag.glsl | 19 +++ gsk/resources/vulkan/opacity-clip.frag.spv | Bin 0 -> 1068 bytes gsk/resources/vulkan/opacity-clip.vert.glsl | 49 +++++++ gsk/resources/vulkan/opacity-clip.vert.spv | Bin 0 -> 4788 bytes gsk/resources/vulkan/opacity.frag.glsl | 19 +++ gsk/resources/vulkan/opacity.frag.spv | Bin 0 -> 1068 bytes gsk/resources/vulkan/opacity.vert.glsl | 34 +++++ gsk/resources/vulkan/opacity.vert.spv | Bin 0 -> 2148 bytes 18 files changed, 533 insertions(+), 2 deletions(-) create mode 100644 gsk/gskvulkaneffectpipeline.c create mode 100644 gsk/gskvulkaneffectpipelineprivate.h create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.frag.glsl create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.frag.spv create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.vert.glsl create mode 100644 gsk/resources/vulkan/opacity-clip-rounded.vert.spv create mode 100644 gsk/resources/vulkan/opacity-clip.frag.glsl create mode 100644 gsk/resources/vulkan/opacity-clip.frag.spv create mode 100644 gsk/resources/vulkan/opacity-clip.vert.glsl create mode 100644 gsk/resources/vulkan/opacity-clip.vert.spv create mode 100644 gsk/resources/vulkan/opacity.frag.glsl create mode 100644 gsk/resources/vulkan/opacity.frag.spv create mode 100644 gsk/resources/vulkan/opacity.vert.glsl create mode 100644 gsk/resources/vulkan/opacity.vert.spv diff --git a/gsk/Makefile.am b/gsk/Makefile.am index 922c727f6d..b92b60bdf9 100644 --- a/gsk/Makefile.am +++ b/gsk/Makefile.am @@ -29,8 +29,9 @@ gsk_private_vulkan_source_h = \ gskvulkanclipprivate.h \ gskvulkancolorpipelineprivate.h \ gskvulkancommandpoolprivate.h \ - gskvulkanlineargradientpipelineprivate.h \ + gskvulkaneffectpipelineprivate.h \ gskvulkanimageprivate.h \ + gskvulkanlineargradientpipelineprivate.h \ gskvulkanmemoryprivate.h \ gskvulkanpipelineprivate.h \ gskvulkanpushconstantsprivate.h \ @@ -44,6 +45,7 @@ gsk_private_vulkan_source_c = \ gskvulkanclip.c \ gskvulkancolorpipeline.c \ gskvulkancommandpool.c \ + gskvulkaneffectpipeline.c \ gskvulkanlineargradientpipeline.c \ gskvulkanimage.c \ gskvulkanmemory.c \ diff --git a/gsk/gskvulkaneffectpipeline.c b/gsk/gskvulkaneffectpipeline.c new file mode 100644 index 0000000000..249185c1cf --- /dev/null +++ b/gsk/gskvulkaneffectpipeline.c @@ -0,0 +1,129 @@ +#include "config.h" + +#include "gskvulkaneffectpipelineprivate.h" + +struct _GskVulkanEffectPipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance; + +struct _GskVulkanEffectInstance +{ + float rect[4]; + float tex_rect[4]; + float value; +}; + +G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanEffectInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, value), + } + }; + static const VkPipelineVertexInputStateCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions), + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription), + .pVertexAttributeDescriptions = vertexInputAttributeDescription + }; + + return &info; +} + +static void +gsk_vulkan_effect_pipeline_finalize (GObject *gobject) +{ + //GskVulkanEffectPipeline *self = GSK_VULKAN_EFFECT_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_effect_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_effect_pipeline_class_init (GskVulkanEffectPipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_effect_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_effect_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_effect_pipeline_init (GskVulkanEffectPipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_effect_pipeline_new (GskVulkanPipelineLayout *layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline) +{ + return sizeof (GskVulkanEffectInstance); +} + +void +gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + float value) +{ + GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data; + + instance->rect[0] = rect->origin.x; + instance->rect[1] = rect->origin.y; + instance->rect[2] = rect->size.width; + instance->rect[3] = rect->size.height; + instance->tex_rect[0] = 0.0; + instance->tex_rect[1] = 0.0; + instance->tex_rect[2] = 1.0; + instance->tex_rect[3] = 1.0; + instance->value = value; +} + +gsize +gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/gskvulkaneffectpipelineprivate.h b/gsk/gskvulkaneffectpipelineprivate.h new file mode 100644 index 0000000000..9a82c0242e --- /dev/null +++ b/gsk/gskvulkaneffectpipelineprivate.h @@ -0,0 +1,32 @@ +#ifndef __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ + +#include + +#include "gskvulkanpipelineprivate.h" + +G_BEGIN_DECLS + +typedef struct _GskVulkanEffectPipelineLayout GskVulkanEffectPipelineLayout; + +#define GSK_TYPE_VULKAN_EFFECT_PIPELINE (gsk_vulkan_effect_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK, VULKAN_EFFECT_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_effect_pipeline_new (GskVulkanPipelineLayout *layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline); +void gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + float value); +gsize gsk_vulkan_effect_pipeline_draw (GskVulkanEffectPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + +G_END_DECLS + +#endif /* __GSK_VULKAN_EFFECT_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index 80b9418373..81bc3193b5 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -10,6 +10,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #define ORTHO_NEAR_PLANE -10000 @@ -319,7 +320,10 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self, { "color-clip-rounded", gsk_vulkan_color_pipeline_new }, { "linear", gsk_vulkan_linear_gradient_pipeline_new }, { "linear-clip", gsk_vulkan_linear_gradient_pipeline_new }, - { "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new } + { "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new }, + { "opacity", gsk_vulkan_effect_pipeline_new }, + { "opacity-clip", gsk_vulkan_effect_pipeline_new }, + { "opacity-clip-rounded", gsk_vulkan_effect_pipeline_new } }; g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 38947ba6bc..70f1de35c5 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -9,6 +9,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkanclipprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #include "gskvulkanimageprivate.h" #include "gskvulkanpushconstantsprivate.h" @@ -27,6 +28,7 @@ typedef enum { GSK_VULKAN_OP_TEXTURE, GSK_VULKAN_OP_COLOR, GSK_VULKAN_OP_LINEAR_GRADIENT, + GSK_VULKAN_OP_OPACITY, /* GskVulkanOpPushConstants */ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS } GskVulkanOpType; @@ -107,6 +109,12 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, case GSK_NOT_A_RENDER_NODE: g_assert_not_reached (); return; + case GSK_BORDER_NODE: + case GSK_INSET_SHADOW_NODE: + case GSK_OUTSET_SHADOW_NODE: + case GSK_SHADOW_NODE: + case GSK_BLEND_NODE: + case GSK_CROSS_FADE_NODE: default: FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name); @@ -161,6 +169,20 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, g_array_append_val (self->render_ops, op); return; + case GSK_OPACITY_NODE: + if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) + pipeline_type = GSK_VULKAN_PIPELINE_OPACITY; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_OPACITY_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_OPACITY_CLIP_ROUNDED; + else + FALLBACK ("Opacity nodes can't deal with clip type %u\n", constants->clip.type); + op.type = GSK_VULKAN_OP_OPACITY; + op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type); + g_array_append_val (self->render_ops, op); + return; + case GSK_CONTAINER_NODE: { guint i; @@ -276,6 +298,41 @@ gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node); } +static GskVulkanImage * +gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self, + GskVulkanRender *render, + GskVulkanUploader *uploader, + GskRenderNode *node, + const graphene_rect_t *bounds) +{ + GskVulkanImage *result; + cairo_surface_t *surface; + cairo_t *cr; + + /* XXX: We could intersect bounds with clip bounds here */ + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ceil (bounds->size.width), + ceil (bounds->size.height)); + cr = cairo_create (surface); + cairo_translate (cr, -bounds->origin.x, -bounds->origin.y); + + gsk_render_node_draw (node, cr); + + cairo_destroy (cr); + + result = gsk_vulkan_image_new_from_data (uploader, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface), + cairo_image_surface_get_stride (surface)); + + cairo_surface_destroy (surface); + + gsk_vulkan_render_add_cleanup_image (render, result); + + return result; +} + static void gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self, GskVulkanOpRender *op, @@ -368,6 +425,18 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_OPACITY: + { + GskRenderNode *child = gsk_opacity_node_get_child (op->render.node); + + op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self, + render, + uploader, + child, + &child->bounds); + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: @@ -411,6 +480,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) n_bytes += op->render.vertex_count; break; + case GSK_VULKAN_OP_OPACITY: + op->render.vertex_count = gsk_vulkan_effect_pipeline_count_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline)); + n_bytes += op->render.vertex_count; + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -478,6 +552,18 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_OPACITY: + { + op->render.vertex_offset = offset + n_bytes; + gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline), + data + n_bytes + offset, + &op->render.node->bounds, + gsk_opacity_node_get_opacity (op->render.node)); + n_bytes += op->render.vertex_count; + } + break; + + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -508,6 +594,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP: case GSK_VULKAN_OP_SURFACE: case GSK_VULKAN_OP_TEXTURE: + case GSK_VULKAN_OP_OPACITY: op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source); break; @@ -577,6 +664,39 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, current_draw_index, 1); break; + case GSK_VULKAN_OP_OPACITY: + if (current_pipeline != op->render.pipeline) + { + current_pipeline = op->render.pipeline; + vkCmdBindPipeline (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline (current_pipeline)); + vkCmdBindVertexBuffers (command_buffer, + 0, + 1, + (VkBuffer[1]) { + gsk_vulkan_buffer_get_buffer (vertex_buffer) + }, + (VkDeviceSize[1]) { op->render.vertex_offset }); + current_draw_index = 0; + } + + vkCmdBindDescriptorSets (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_layout_get_pipeline_layout (layout), + 0, + 1, + (VkDescriptorSet[1]) { + gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index) + }, + 0, + NULL); + + current_draw_index += gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (current_pipeline), + command_buffer, + current_draw_index, 1); + break; + case GSK_VULKAN_OP_COLOR: if (current_pipeline != op->render.pipeline) { diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h index 72c4314492..6de38d2747 100644 --- a/gsk/gskvulkanrenderprivate.h +++ b/gsk/gskvulkanrenderprivate.h @@ -17,6 +17,9 @@ typedef enum { GSK_VULKAN_PIPELINE_LINEAR_GRADIENT, GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP, GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED, + GSK_VULKAN_PIPELINE_OPACITY, + GSK_VULKAN_PIPELINE_OPACITY_CLIP, + GSK_VULKAN_PIPELINE_OPACITY_CLIP_ROUNDED, /* add more */ GSK_VULKAN_N_PIPELINES } GskVulkanPipelineType; diff --git a/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl b/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl new file mode 100644 index 0000000000..91c1e54437 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip-rounded.frag.glsl @@ -0,0 +1,64 @@ +#version 420 core + +struct RoundedRect { + vec4 bounds; + vec4 corners; +}; + +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec2 inTexCoord; +layout(location = 2) in flat float inOpacity; +layout(location = 3) in flat vec4 inClipBounds; +layout(location = 4) in flat vec4 inClipWidths; + +layout(set = 0, binding = 0) uniform sampler2D inTexture; + +layout(location = 0) out vec4 color; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +float clip(vec2 pos, RoundedRect r) { + vec2 ref_tl = r.bounds.xy + vec2( r.corners.x, r.corners.x); + vec2 ref_tr = r.bounds.zy + vec2(-r.corners.y, r.corners.y); + vec2 ref_br = r.bounds.zw + vec2(-r.corners.z, -r.corners.z); + vec2 ref_bl = r.bounds.xw + vec2( r.corners.w, -r.corners.w); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_br = distance(pos, ref_br); + float d_bl = distance(pos, ref_bl); + + float pixels_per_fragment = length(fwidth(pos.xy)); + float nudge = 0.5 * pixels_per_fragment; + vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - r.corners + nudge; + + bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y, + pos.x > ref_tr.x && pos.y < ref_tr.y, + pos.x > ref_br.x && pos.y > ref_br.y, + pos.x < ref_bl.x && pos.y > ref_bl.y); + + float distance_from_border = dot(vec4(is_out), + max(vec4(0.0, 0.0, 0.0, 0.0), distances)); + + // Move the distance back into pixels. + distance_from_border /= pixels_per_fragment; + // Apply a more gradual fade out to transparent. + //distance_from_border -= 0.5; + + return 1.0 - smoothstep(0.0, 1.0, distance_from_border); +} + +vec4 +opacity (vec4 color, float value) +{ + return color * value; +} + +void main() +{ + RoundedRect r = RoundedRect(vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths); + + color = opacity (texture (inTexture, inTexCoord), inOpacity) * clip (inPos, r); +} diff --git a/gsk/resources/vulkan/opacity-clip-rounded.frag.spv b/gsk/resources/vulkan/opacity-clip-rounded.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..42fa1561845f65cd5e79379ade471416c9cfd6ef GIT binary patch literal 5584 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 literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/opacity-clip.vert.glsl b/gsk/resources/vulkan/opacity-clip.vert.glsl new file mode 100644 index 0000000000..4cf0f13b64 --- /dev/null +++ b/gsk/resources/vulkan/opacity-clip.vert.glsl @@ -0,0 +1,49 @@ +#version 420 core + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inTexRect; +layout(location = 2) in float inOpacity; + +layout(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out vec2 outTexCoord; +layout(location = 1) out flat float outOpacity; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +vec4 intersect(vec4 a, vec4 b) +{ + a = vec4(a.xy, a.xy + a.zw); + b = vec4(b.xy, b.xy + b.zw); + vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw)); + if (any (greaterThanEqual (result.xy, result.zw))) + return vec4(0.0,0.0,0.0,0.0); + return vec4(result.xy, result.zw - result.xy); +} + +void main() { + vec4 rect = intersect(inRect, push.clip_bounds); + vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw, + rect.zw / inRect.zw); + texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy, + inTexRect.zw * texrect.zw); + outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex]; + outOpacity = inOpacity; +} diff --git a/gsk/resources/vulkan/opacity-clip.vert.spv b/gsk/resources/vulkan/opacity-clip.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..81aa4f6f85859a436f5b6148e435eeadcc49f805 GIT binary patch literal 4788 zcmZ9OhjUa_6viK<5Q-?$tQf?Cg4nR4fTFHwoJ6tD=qBuL$ZFV)*-gX_BKF>U@4a{M z&(d*5$KUVe9lVq4eB5)s`<-*oJ@>wi9Wz(V%CZ^!*OUE`O^pTFO#CdHn|0@Nsc%c) znpV5IX6+fLsFacR=quH5h1 z-|H2*Le2ji4?R05(Rl~zHYS|?mm5g9j)EIxE^%Jpjymh{G5Cf~1nw0*l5?n+3%%ci z^}Dz6_9D)s);`QH*0fWt-;chz7V@w2a$>AcdkI!Ib1zs*ZqKXlx6#YLJb?H9L(&R{JO&TyOJ~Bc@c1|rUqjd133|z zCD>WEb3oEA?vTQl5AING{V8sCUdLhh?qLpNgtpp6oV1kto!p;yGIjRVbjdzl z0iw2;J?G8vGk_Y;sqfpAI|P4_*)@B=j8hLW4+6P>dA8zv53ZX>zfy4azlz-p%xiD- z`AN)uU56S4j~wz*5#_Za$H3tqkZ>Yu~O%ry%9D{CIt)L6TG#5b|!`iZcgV?a(g>`7>E!%ns1 z_;SLY*(Y~=hNH2VB}XXcdORd9D=Ta#$}+r z?1}Hmyo1cUz)leR+>dSCmBe`GyMde|xCgN1JnsO#uz!1iTG#xB{cU)L9IibG+((VI zJjDDkxCdB^wd$+04r3k#Y5yK8IC)3f>&NkZ2XQY?V9N=I+THAH-<|~KQWJYUg`LJf zjV~wSt{yJppMf)nnuvcEJFWFOd^r*Ep?w}M-RlK>IT6~}>qR(osfpgdgl!Fu;9ka- z^PIuGf^EDbxL2{|)WyBMhHXxB7^BAf@Vj#@>V5;;-<9a`o7i%~k>1B!_^I}7d^r(k zjJ)r_xmVjJJ-E-Yjduk11-6{JxQ{Qf&1nu})Wm(b7H9khJFWX$d^zDT zXK25}PPO0T%ZWIn+A97Jpbh*^Cz*c)3xT|v`OH57`RL2f*yfavd-(<1nq0H~ubJh{ z(apRM>;W7ODNYjiF8aXhwti+-%cmJ<$hhV}&PRC^-6oN%PtRrslPHNKpf z-j9>u%%vvIv+>5qyYQ{woN8mwbFkAr&&8J$(W}s|gG={34_{7%HugLp z&KkUXbE=IVt;e<|M{pakqt4(q!kNbr+y&T?JKo!caOO0}Mxe(2`u({U^>4zKi}!XB zww!QSZ)h*ZPPLcd%ZWJaK7Jc6#or9frRG(BQ%cO20r@|vqmS9~H*4~j137;$wEtzk zqVVOThJNg{h5>vz;YjPf5ol*gIRDecKQ=+p#UD!|~<#?6#hs4L^N=v1@Hd zgtMo(O=;vN&I%mQBrhd>NmpEaDxzCknazGHaMQLe97o|~5{`dF$$TE&)^~Xt7_6Bm`nKYX|E2v1*j_ILYd}_siLEH2XL*cssHuWnNa&;78KS zIA5rY!}NXc59~-dE3VR?^`csF0ymeleJ{&uN?hRP%!?6~i?ZSH=c`<84y$)R%bEx_!pr~i&L zHU#|8-{JH%-?qo_@WFX1%_|^ge`E=y;W8)RVm%u(^Zmf*^3&rB z3H^cTf&EkeT3O(|mcYS&p$g=~2A`hZNazP2xxwG$A@;3=H%tsZIP4btUrqQ`!VGZX sarj1G#G`lKId}TzjWZi>h1$gIN#Lw|>FN&em(RJcI~?r)6bq*2e>5jiTL1t6 literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/opacity.vert.glsl b/gsk/resources/vulkan/opacity.vert.glsl new file mode 100644 index 0000000000..7e12d41e1a --- /dev/null +++ b/gsk/resources/vulkan/opacity.vert.glsl @@ -0,0 +1,34 @@ +#version 420 core + +layout(location = 0) in vec4 inRect; +layout(location = 1) in vec4 inTexRect; +layout(location = 2) in float inOpacity; + +layout(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out vec2 outTexCoord; +layout(location = 1) out flat float outOpacity; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 offsets[6] = { vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0) }; + +void main() { + vec2 pos = inRect.xy + inRect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + + outTexCoord = inTexRect.xy + inTexRect.zw * offsets[gl_VertexIndex]; + outOpacity = inOpacity; +} diff --git a/gsk/resources/vulkan/opacity.vert.spv b/gsk/resources/vulkan/opacity.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..d0c9b86128ce45422d4e4766a8323c08c7922306 GIT binary patch literal 2148 zcmZ9M*-{fh6ownJuqlYhq9O)STv$W}M3GIzKowQQrM!)p3}mXpOe&cm-06i6;5+z` z-dN@T^-SZGojRQJ|7Ypbr+dhBPIVd6pS+_shkDgW~>9xzcEq zThV#lE7$$ND_8xdSBd;nkGSqsoF7!`?P@w8r-=0aV7dyAj#^&SGCA!zEZhjOv$j7! zc(3wCIB$DBu9rV~&B#033##5(%ug#ve93FZEYU_e$PL}`bSECwym(6GTmalpKam|*t z=b97W(4JDlIXnBX9ewo9w!^SlwH$Zh2cqKRTaLR?+(F~8;z#FkE_dYz7nJTUp4)_Y z7MMHklRT2_s*;-v9IL3g!*Pz?)Y)?u=PqV3CCs7*^I+*wnky2=F(cwOQyg{SN-2)n zzAWC<**<2h^)MHK{Ben=pT%4 zSh!odAYsiUxJNcIZ-$C}E8W^M=W#*9leS z-8c^3)t!~i9pR@gcrM}CcRsPn1usjpr^{bSFg=qG=3Np4W+uGL4hi{hr15c1{9xWG z9R9b`#5zB?m~hK_7rZ~t#3JXn7`{JhabNsjq?dJhd0*V|ntb$oUBdkwD1w+92?x(& zUl)5*b~<)k7!IKa_9oWdG55HoP9~-ANZ7j|A%?xCB=A3yw|!SOHQ~P}+&$U!gpd9? z3mkR1hsP4`hI^(icd{UXcl$h%P2M}@FvF)3IF{p{$%f;+C3VMa7A3^u<6Gi8`KcQC zmL%*$481H%KbP?S=!IUv#L)*is}k